﻿using System;
using System.Collections;
using System.Text;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Xml;
using System.Diagnostics;
using System.Threading;
using System.Text.RegularExpressions;

namespace Simulated_Annealing
{
    class Program                                                
    {
      

        static void Main(string[] args)                         //Where the main program runs...starts and stops the clock
        {
            
            Random random = new Random();

            Stopwatch watch = new Stopwatch();                  //create a new stopwatch instance to record time
            watch.Start();                                      //start the stopwatch recording time
            string inputfile; 

            // If there are command line arguments, the first one is the file name
            if (args.Length != 0)
            { inputfile = args[0];}
            else
            { inputfile = "test1.vrp"; }

            VRP network = new VRP();                            //initialize VRP problem
            List<Nodes> nodes= new List<Nodes>();
            network.lambda = 1.0F;                              //initialize lambda = 1 for parser
  
                      
            //create a new parser object
            TSPLIBParser myParser = new TSPLIBParser(inputfile);
            myParser.Parse();

            //sets network to parser values
            network.capacity = myParser.Capacity;
            network.costmatrix = network.ODmatrix(myParser); // calculate the OD matrix
            network.demandarray = myParser.Demands;
            network.numnodes = myParser.Dimension;
            network.optimal_solution = myParser.BestKnown;
            network.error = false;     
            //

            if (network.error == true)                          //if there is an error in the input file, report it
            {
                Console.WriteLine("There is an error in the input file!");
                return;
            }
            Saving.Clark_Wright(network,nodes);                       //calls the Saving algorithm with the current input file specification 
            network.route_clean(network);



            VRP originalnetwork = new VRP(network); //stores original network
       
            SimA.Nfeas = VRP.find_Nfeas(network, random);
            int numfeas = SimA.Nfeas;
            SimA.Initialize(network.numnodes, numfeas, network, random); //initialize all the variables in simulated annealing class
            List<double> initialtemps = new List<double>(); 
            initialtemps = VRP.find_temp(network, random);
            SimA.T_f = initialtemps[0];
            SimA.T_s = initialtemps[1];
            int R_check;
            int Rstop = 3;  //stopping criteria
            R_check = SimA.R;

            VRP s_current = new VRP(network); //this will be used in the while loop to store the current VRP solution we examin
            VRP s_best = new VRP(network); //this will be used in the while loop to store the best VRP solution we've found so far
            s_current.route_clean(s_current);
            s_best.route_clean(s_best);

            while(watch.ElapsedMilliseconds<300000)

            {
               // while (R_check < Rstop) 
                // {
                //do the following each time you re-enter the while loop
                s_current.route_clean(s_current);
                int[,] routepairlist;
                routepairlist = Neighborhood.routepairlist(s_current,random); //generate a new route pair list that corresponds to s_current

               int counter = 0;  //counter: counts the number of times we rejected in a loop of the route pairs during one neighborhood search

               int routelengthcheck= routepairlist.GetLength(0);

               for (int i = 0; i < routepairlist.GetLength(0); i++) //goes through each in the route list of a particular neighborhood
                {

                    s_current.route_clean(s_current);
                    //calls the neighborhood function to create s_neighborhood as a change from s_current
                    VRP s_neighbor = new VRP(Neighborhood.Create_Neighborhood(s_current, i, routepairlist, nodes)); 
                    s_neighbor.route_clean(s_neighbor);

                    //here we store the best neighborhood we have so far
                    if (s_current.totalcost(s_current.routes, s_current) < s_best.totalcost(s_best.routes, s_best))
                    {
                        //we want to make s_best the s_current
                        s_best = new VRP(s_current);
                    }
                    // else we continue

                    double delta = s_neighbor.totalcost(s_neighbor.routes, s_neighbor) - s_current.totalcost(s_current.routes, s_current);//This will be the delta you want for your SA part, so copy this          


                    //BEGIN SIMULATED ANNEALING PROCESS

                    int acceptCheck = SimA.Run(delta,routepairlist.GetLength(0),counter);  //this will pass the delta to the simulated annealing class and do acceptance rejection
                                //SimA.Run will also update the temperature accordingly
                                //SimA.Run also accepts the size of the route list so that it can check for what kind of temperature update to do
                  
                    R_check = SimA.R;  //just make sure the current R value is most up to date from the SimA class

                    
                    if (acceptCheck == 1)  //this means we did accept the new neighborhood
                    {
                        s_current = new VRP(s_neighbor);
                        
                        break;   //this takes us out of the if loop for routelist looping and back to the while loop
                    }
                    if (acceptCheck == 0) //this means we did not accept the new neighborhood
                    {
                        counter += 1;   //increment the nubmer of times we rejected
                        
                        continue;   //this takes us to the top of the list to the next pair on the routelist
                    }

 
                }  //end for loop for the route pairs

               //double elapsedMS1 = watch.ElapsedMilliseconds;       //compute the time in milliseconds
              // if (elapsedMS1 > 120000)
               //{
                //   break;
               //}


       //     }  //end while for R check

        }   //end time check while

        
            Feasibility.check(s_best);   //here we make sure all the values stored in the VRP network for our final solution are not null

            watch.Stop();                                       //after the algorithm is complet, stop the clock
           double elapsedMS = watch.ElapsedMilliseconds;       //compute the time in milliseconds
           RouteWrite.Outputroutes(originalnetwork, s_best, elapsedMS, inputfile);       //output the results using the RouteWrite class
          
        }

    }
}
